/*
 * opMethods.c
 *
 *  Created on: Jun 4, 2011
 *      Author: Craig Markham
 *		Class:  TCSS 371
 *		Assignment:
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned short int strToNum (char string[]) {
	
	if (string[0] == '0' && tolower (string[1]) == 'x') {
		return strtol(string, NULL, 16);
	} else if (tolower (string[0]) == 'x') {
		return strtol(&string[1], NULL, 16);
	} else if (tolower (string[0] = 'b')) {
		return strtol(&string[1], NULL, 2);
	} else if (string[0] = '#') {
		return strtol(&string[1], NULL, 10);
	} else {
		return strtol(string, NULL, 10);
	}

}

unsigned short int regToNum (char reg[]) {
	int i;
	
	if (tolower (reg[0]) == 'r' && reg[2] == '\0') {
		i = atol (&reg[1]);
		return i;
	} else {
		printf("ERROR\n");
		return -1;
	}

}

unsigned short int opADD (char dr[], char sr1[], char other[]) {
	if (tolower (other[0] == 'r')) {
		return 0x1000 | (regToNum (dr) << 9) | (regToNum (sr1) << 6) | regToNum (other);
	} else {
		return 0x1020 | (regToNum (dr) << 9) | (regToNum (sr1) << 6) | strToNum (other);
	}
}

unsigned short int opAND (char dr[], char sr1[], char other[]) {
	if (tolower (other[0] == 'r')) {
		return 0x5000 | (regToNum (dr) << 9) | (regToNum (sr1) << 6) | regToNum (other);
	} else {
		return 0x5020 | (regToNum (dr) << 9) | (regToNum (sr1) << 6) | strToNum (other);
	}
}

unsigned short int opBR (char cc[], char offset[]) {
	int i;
	int n;
	int z;
	int p;
	
	n = 0;
	z = 0;
	p = 0;
	
	for (i = 0; i < strlen(cc); i++) {
		if (cc[i] == 'n') {
			n = 1;
		} else if (cc[i] == 'z') {
			z = 1;
		} else if (cc[i] == 'p') {
			p = 1;
		}
	}
	return 0x0000 | (n << 11) | (z << 10) | (p << 9) | strToNum (offset);
}

unsigned short int opJMP (char br[]) {
	return 0xC000 | (regToNum (br) << 6);
}

unsigned short int opJSR (char offset[]) {
	return 0x4800 | strToNum (offset);
}

unsigned short int opJSRR (char br[]) {
	return 0x4000 | (regToNum (br) << 6);
}

unsigned short int opLD (char dr[], char offset[]) {
	return 0x2000 | (regToNum (dr) << 9) | strToNum (offset);
}

unsigned short int opLDI (char dr[], char offset[]) {
	return 0xA000 | (regToNum (dr) << 9) | strToNum (offset);
}

unsigned short int opLDR (char dr[], char br[], char offset[]) {
	return 0x6000 | (regToNum (dr) << 9) | (regToNum (br) << 6) | strToNum (offset);
}

unsigned short int opLEA (char dr[], char offset[]) {
	return 0xE000 | (regToNum (dr) << 9) | strToNum (offset);
}

unsigned short int opNOT (char dr[], char sr[]) {
	return 0x903F | ( regToNum (dr) << 9) | (regToNum (sr) << 6);
}

unsigned short int opRET () {
	return 0xC1C0;
}

unsigned short int opRTI () {
	return 0x8000;
}

unsigned short int opST (char sr[], char offset[]) {
	return 0x3000 | (regToNum (sr) << 9) | strToNum (offset);
}

unsigned short int opSTI (char sr[], char offset[]) {
	return 0xB000 | (regToNum (sr) << 9) | strToNum (offset);
}

unsigned short int opSTR (char sr[],char br[], char offset[]) {
	return 0x7000 | (regToNum (sr) << 9) | (regToNum (br) << 6) | strToNum (offset);
}

unsigned short int  opTRAP (char vect[]) {
	return 0xF000 | strToNum (vect);
}

unsigned short int opGETC () {
	char vect[] = "x20";
	return opTRAP(vect);
}

unsigned short int opHALT () {
	char vect[] = "x25";
	return opTRAP(vect);
}

unsigned short int opIN () {
	char vect[] = "x23";
	return opTRAP(vect);
}

unsigned short int opOUT () {
	char vect[] = "x21";
	return opTRAP(vect);
}

unsigned short int opPUTS () {
	char vect[] = "x22";
	return opTRAP(vect);
}

unsigned short int opPUTSP () {
	char vect[] = "x24";
	return opTRAP(vect);
}

unsigned short int opFILL (char address[]) {
	return 0x000 | strToNum(address);
}

unsigned short int opSTRINGZ (char character) {
	return character;
}

unsigned short int *opNEG (char dr[], char sr[]) {
	unsigned short int *op;
	
	op = (unsigned short int *)malloc(sizeof(unsigned short int) * 2);
	
	op[0] = opNOT(dr, sr);
	op[1] = opADD(dr, dr, "#1");
	return op;
}

unsigned short int *opPUSH (char sr[]) {
	unsigned short int *op;
	
	op = (unsigned short int *)malloc(sizeof(unsigned short int) * 2);
	
	op[0] = opADD("R6", "R6", "#-1");
	op[1] = opSTR(sr, "R6", "#0");
	return op;
}

unsigned short int *opPOP (char dr[]) {
	unsigned short int *op;
	
	op = (unsigned short int *)malloc(sizeof(unsigned short int) * 2);
	
	op[0] = opLDR(dr, "R6", "#0");
	op[1] = opADD("R6", "R6", "#1");
	return op;
}